﻿using System.Collections.Generic;
using HCore;

namespace MEat
{
    public partial class MEatGame
    {
        private class ClientBattleState : State<MEatGame>
        {
            private readonly List<MoveEntity> _moveEntities;

            public ClientBattleState(MEatGame owner) : base(owner)
            {
                _moveEntities = new List<MoveEntity>();
            }

            public override void Enter()
            {
                _moveEntities.Clear();

                _owner.Log("Enter ClientBattleState");
                
                _owner._inBattle = true;
                _owner.timer.Start();
                foreach (var kv in _owner.commandMgr.serverProxies)
                {
                    AddDummy(kv.Key, Vector3.zero, Vector3.forward);
                }
                //
                // AddPendulum();
                // AddSpring();
            }

            public override void Execute()
            {
                while (_owner.timer.ReadyForNextFrame() && CheckSync())
                {
                    // 检测输入并发送命令到服务器
                    _owner.commandMgr.Update(CalChecksum());
                    InternalUpdate(_owner.timer.deltaTime);
                    _owner.timer.IntoNextFrame();
                }
            }

            private void InternalUpdate(Fix deltaTime)
            {
                foreach (var dummy in _moveEntities)
                {
                    dummy.Update(deltaTime);
                }
            }

            private bool CheckSync()
            {
                if (_owner.timer.frameCount < GameDefine.COMMAND_DELAY_TURN)
                {
                    return true;
                }

                if (_owner.timer.frameCount % GameDefine.FRAMES_PER_TURN != 0)
                {
                    return true;
                }

                int turnCount = _owner.timer.frameCount / GameDefine.FRAMES_PER_TURN;
                foreach (var kv in _owner.commandMgr.serverProxies)
                {
                    int playerId = kv.Key;
                    if (!_owner.commandMgr.CheckTurnData(playerId, turnCount))
                    {
                        _owner.Log("CheckSync wait " + turnCount);
                        return false;
                    }
                }

                return true;
            }

            public int CalChecksum()
            {
                int checksum = 0;
                foreach (MoveEntity m in _moveEntities)
                {
                    checksum ^= m.CalculateChecksum();
                }

                return checksum;
            }

            private void AddDummy(int playerId, Vector3 position, Vector3 forward)
            {
                _owner.Log("MEat Add Dummy playerId: " + playerId);
                Dummy dummy = new Dummy(EntityType.Dummy, _owner);
                dummy.playerId = playerId;
                dummy.position = position;
                dummy.forward = forward;
                dummy.maxSpeed = 4;
                dummy.maxForce = 10;
                _owner.entityMgr.RegisterEntity(dummy);
                _moveEntities.Add(dummy);
            }

            public void AddPendulum()
            {
                _owner.Log("MEat Add Pendulum");
                Pendulum pendulum = new Pendulum(EntityType.Pendulum, _owner);
                pendulum.r = 5;
                pendulum.angle = FixMath.PI / 3 * 2;
                _owner.entityMgr.RegisterEntity(pendulum);
                _moveEntities.Add(pendulum);
            }

            public void AddSpring()
            {
                _owner.Log("MEat Add Spring");
                Spring spring = new Spring(EntityType.Spring, _owner);
                spring.k = 5;
                spring.restLength = 5;
                spring.position = Vector3.up * 10 + Vector3.back * 5;
                spring.anchorPosition = spring.position;
                _owner.entityMgr.RegisterEntity(spring);
                _moveEntities.Add(spring);
            }

            public override void Exit()
            {
                foreach (var m in _moveEntities)
                {
                    _owner.entityMgr.RemoveEntity(m);
                    m.Dispose();
                }

                _moveEntities.Clear();

                _owner._inBattle = false;
                _owner.Log("Exit ClientBattleState");
            }
        }
    }
}